package com.lagou.rpc.consumer.proxy;

import com.lagou.rpc.consumer.anno.RpcConsumerService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.RestController;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Component
public class RpcClientProxyProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }

    /**
     * spring后置处理器完成Bean对象注入IOC容器
     *
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Class<?> beanClass = bean.getClass();
        //首先此处我们仅在 controller 完成代理注入
        if (beanClass.isAnnotationPresent(RestController.class) || beanClass.isAnnotationPresent(Controller.class)) {
            //获取到 controller 中定义的属性
            Field[] fields = beanClass.getDeclaredFields();
            //过滤得到被 @RpcConsumerService 注入的属性
            List<Field> remoteRpcServices = Arrays.stream(fields)
                    .filter(field -> field.isAnnotationPresent(RpcConsumerService.class))
                    .collect(Collectors.toList());
            //循环上面得到的属性字段并使用 jdk 代理注入
            remoteRpcServices.forEach(remoteRpcService -> {
                Class<?> fieldType = remoteRpcService.getType();
                //具体的注入方式和方法
                Object proxy = RpcClientProxy.createProxy(fieldType);
                remoteRpcService.setAccessible(true);
                ReflectionUtils.setField(remoteRpcService, bean, proxy);
            });
        }
        return bean;
    }
}
